# coding: utf-8

from google.appengine.api import urlfetch
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app

import os, logging, urlparse, pickle
import utils
from transform_content import transform as transform_content

TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), u'templates/')

def render_template(template_file, context=None):
    path = os.path.join(TEMPLATE_DIR, template_file)
    return template.render(path, context)

class BaseRequestHandler(webapp.RequestHandler):
    def render_to_response(self, template_file, context=None):
        return self.response.out.write(render_template(template_file, context))

class HomePage(BaseRequestHandler):
    def get(self):
        return self.render_to_response(u'index.html')

class FetchServicePage(webapp.RequestHandler):
    '''提供urlfetch服务，代理服务器会将请求转发给它。
    请求内容使用pickle编码，编码内容为：
    {
        'method': method,
        'url': url,
        'payload': payload,
        'headers': headers,
    }, 响应
    '''
    def post(self):
        req = pickle.loads(self.request.body)
        result = urlfetch.fetch(req['url'], payload=req.get('payload', ''), headers=req.get('headers', {}), follow_redirects=False)
        self.response.set_status(result.status_code)
        headers = {}
        for k, v in result.headers.iteritems():
            if k in headers:
                headers[k] = v
                self.response.headers.add_header(k, v)
            else:
                self.response.headers[k] = v
        self.response.out.write(result.content)

class ProxyPage(BaseRequestHandler):
    #IGNORE_REQUEST_HEADERS = ['host']         # ignored request headers
    IGNORE_RESPONSE_HEADERS = []        # ignored response headers

    def _fetch(self, encoded_url, method='GET'):
        # decode url
        self._url, self._seed, self._options = utils.decode_url(encoded_url)
        self._url = utils.append_query_string(self._url, self.request.query_string) 

        # decode request cookies
        headers = {}
        cookies = []
        for cookie_name, cookie_value in self.request.cookies.iteritems():
            cookieinfo = utils.decode_cookiename(cookie_name)
            if utils.accept_cookie(cookieinfo, self._url):
                cookies.append('%s=%s' % (cookieinfo[1], cookie_value))
        if cookies:
            headers['Cookie'] = ';'.join(cookies)

        # fetch
        logging.info('request url: %s, payload: %s, headers: %s' % (self._url, self.request.body, headers))
        result = urlfetch.fetch(self._url, payload=self.request.body, headers=headers, method=method, follow_redirects=False)
        logging.info('response headers: %s' % result.headers)

        # process response
        if result.status_code == 200:
            self._set_resp_headers(result)
            if utils.is_html(result.headers.get('content-type', '')):
                content = transform_content(result.content, self._url, self._seed, self._options);
                self.response.out.write(content)
            else:
                self.response.out.write(result.content)
        elif result.status_code in (301, 302):
            self.response.set_status(result.status_code)
            self._set_resp_headers(result)
        else:   # error
            self.render_to_response(u'index.html')

    def _set_resp_headers(self, fetchresult):
        for k, v in fetchresult.headers.iteritems():
            if k.lower() in self.IGNORE_RESPONSE_HEADERS:
                continue
            if k.lower() == 'location':     # process redirect location header
                url = urlparse.urljoin(self._url, v)
                v = utils.encode_url(url, self._seed, self._options)
                v = '/p/%s/' % v
            elif k.lower() == 'set-cookie': # process cookies, encode cookie name with domain and path
                cookie = utils.parse_cookie(v, self._url)
                if cookie:
                    self.response.headers.add_header('Set-Cookie', '%s;path=/' % utils.encode_cookie(cookie))
                continue
            self.response.headers[k] = v

    def get(self, encoded_url):
        self._fetch(encoded_url)

    def post(self, encoded_url):
        self._fetch(encoded_url, method='POST')


#class ProxyServerPage(webapp.RequestHandler):
    #IGNORE_REQUEST_HEADERS = ['proxy-connection']         # ignored request headers

    #def _fetch(self):
        #url = self.request.uri

        #headers = {}
        #for k, v in self.request.headers.iteritems():
            #if k.lower() in self.IGNORE_REQUEST_HEADERS:
                #continue
            #headers[k] = v
        #req = {
            #'url': url,
            #'headers': headers,
            #'method': self.request.method,
            #'payload': self.request.body,
        #}
        #headers = {
            #'content-type': 'application/octet-stream',
        #}
        #result = urlfetch.fetch('http://onlinep4y.appspot.com/f/', payload=pickle.dumps(req), method='POST', headers=headers, follow_redirects=False)
        #logging.info('response result: %s' % result.content)

        #self.response.set_status(result.status_code)
        #for k, v in result.headers.iteritems():
            #self.response.headers[k] = v
        #self.response.out.write(result.content)

    #def get(self):
        #self._fetch()

    #def post(self):
        #self._fetch()


application = webapp.WSGIApplication(
    [
        ('/', HomePage),
        #('/static/(.*)', StaticPage),
        (r'/p/(?P<encoded_url>[-_.\w]+)/', ProxyPage),
        (r'/f/', FetchServicePage),
    ],
    debug=True
)

def main():
    run_wsgi_app(application)

if __name__ == '__main__':
    main()

